﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
using Newtonsoft.Json;

namespace Nonocast.Http {
	// http://www.jz123.cn/uploads/allimg/100708/0705260.jpg
	public interface ActionResult {
		void ExecuteResult(NetworkStream stream);
	}

	public abstract class ActionResultBase : ActionResult {
		public abstract void ExecuteResult(NetworkStream stream);

		protected void Write(NetworkStream stream, string message) {
			var buffer = Encoding.UTF8.GetBytes(message);
			Write(stream, buffer, 0, buffer.Length);
		}

		protected void Write(NetworkStream stream, byte[] buffer, int offset, int size) {
			stream.Write(buffer, offset, size);
		}
	}

	public class EmptyActionResult : ActionResultBase {
		public override void ExecuteResult(NetworkStream stream) {
			Write(stream, "HTTP/1.1 200 OK\r\n\r\n");
		}
	}

	public class ContentResult : ActionResultBase {
		public ContentResult(string message) {
			this.message = message;
		}

		public override void ExecuteResult(NetworkStream stream) {
			string template = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {0}\r\n\r\n{1}";
			var response = string.Format(template, Encoding.UTF8.GetByteCount(message), message);
			Write(stream, response);
		}

		private string message;
	}

	public class FilePathResult : ActionResultBase {
		public FilePathResult(string filepath) {
			this.filepath = filepath;
		}

		public override void ExecuteResult(NetworkStream stream) {
			string template = "HTTP/1.1 200 OK\r\nContent-Type: image/{0}\r\nContent-Length: {1}\r\n\r\n";
			var response = string.Format(template, Path.GetExtension(filepath).TrimStart(new char[] { '.' }), new FileInfo(filepath).Length);
			Write(stream, response);
			var img = File.ReadAllBytes(filepath);
			stream.Write(img, 0, img.Length);
		}

		private string filepath;
	}

	public class JsonResult : ActionResultBase {
		public JsonResult(object data) {
			this.data = data;
		}

		public override void ExecuteResult(NetworkStream stream) {
			var json = JsonConvert.SerializeObject(data, Formatting.Indented);
			string template = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {0}\r\n\r\n{1}";
			var response = string.Format(template, Encoding.UTF8.GetByteCount(json), json);
			Write(stream, response);
		}

		private object data;
	}

	public class HtmlResult : ActionResultBase {
		public HtmlResult(string filepath) : this(filepath, null, null) { }

		public HtmlResult(string filepath, object model) : this(filepath, model, null) { }

		public HtmlResult(string filepath, object model, Dispatcher dispatcher) {
			this.filepath = filepath;
			this.model = model;
			this.dispatcher = dispatcher;
		}

		public override void ExecuteResult(NetworkStream stream) {
			var fullpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filepath);
			if (File.Exists(fullpath)) {
				var razor = File.ReadAllText(fullpath, Encoding.UTF8);
				string html = string.Empty;

				if (dispatcher != null) {
					dispatcher.Invoke(delegate {
						html = RazorEngine.Razor.Parse(razor, model);
					});
				} else {
					html = RazorEngine.Razor.Parse(razor, model);
				}

				string template = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {0}\r\n\r\n{1}";
				var response = string.Format(template, Encoding.UTF8.GetByteCount(html), html);
				Write(stream, response);
			}
		}

		private string filepath;
		private object model;
		private Dispatcher dispatcher;
	}
}
